﻿using System;
using System.Collections.Generic;
using System.Linq;
using Keyki.NefClass.Kernel.Data;
using Keyki.NefClass.Kernel.Fuzzy.Rulles;

namespace Keyki.NefClass.Kernel.Fuzzy.ChooceRule
{
	public abstract class AbstractRule
	{
		/// <summary>
		/// Procedure for choose rules
		/// </summary>
		/// <param name="antecedents">list of antecedents</param>
		/// <param name="dataSet">dataSet</param>
		/// <param name="rulles"></param>
		/// <param name="count">number of rulles in finish rule base</param>
		public abstract void Procedure(List<Antecedent> antecedents, DataSet dataSet, ref List<FuzzyRule> rulles, int count);

		protected void CreateAllRules(List<Antecedent> antecedents, DataSet dataSet, out List<FuzzyRule> rulles)
		{
			Dictionary<int, List<ChooseContainer>> fulfilments = new Dictionary<int, List<ChooseContainer>>(dataSet.CountClasses);

			int count = Convert.ToInt32(dataSet.GetAt(0).Count * Core.NefClass.TraineeSample);
			List<ChooseContainer> tmpList = null;
			rulles = new List<FuzzyRule>(antecedents.Count);

			for (int i = 0; i < count; i++)
			{
				var dataRow = dataSet.DataRow(i);
				var classId = dataSet[i];
				tmpList = new List<ChooseContainer>(antecedents.Count);

				for (int j = 0; j < antecedents.Count; j++)
				{
					var container = new ChooseContainer(j, antecedents[j].Compute(dataRow));
					tmpList.Add(container);
				} //for j

				AddOrSum(fulfilments, classId, tmpList);
			} //for i

			for (int i = 0; i < antecedents.Count; i++)
			{
				var select = from fulfilment in fulfilments
										 from value in fulfilment.Value
										 where value.AntecedentId == i
										 select value.Fulfiment;

				int classId = select.ArgMax();
				var max = select.ElementAt(classId);
				var sum = select.Sum();

				var fuzzyRulle = new FuzzyRule(classId);
				fuzzyRulle.Antecedent = antecedents[i];
				fuzzyRulle.Performance = 2 * max - sum;
				rulles.Add(fuzzyRulle);
			} //for i
		}//CreateAllRules

		/// <summary>
		/// Add element to dictiony if it doesn't exist, otherwise count sum between old and new value
		/// </summary>
		/// <param name="fulfilments">Dictionary</param>
		/// <param name="classId">Dictionary key</param>
		/// <param name="valueList">Dictionary value</param>
		private void AddOrSum(Dictionary<int, List<ChooseContainer>> fulfilments, int classId, List<ChooseContainer> valueList)
		{
			if (fulfilments.ContainsKey(classId))
			{
				var tmpList = fulfilments[classId];

				for (int i = 0; i < tmpList.Count; i++)
				{
					foreach (var container in valueList)
					{
						if (container.AntecedentId == tmpList[i].AntecedentId)
						{
							tmpList[i].Fulfiment += container.Fulfiment;
							break;
						}//if container
					}//foreach
				}//for i
			}//if fulfilments
			else
			{
				fulfilments.Add(classId, valueList);
			}
		}//AddOrSum

	}//AbstractRule
}//Keyki.NefClass.Kernel.Fuzzy
